#include <scheme.h>
#include <linux/netlink.h>  
#include <linux/skbuff.h>  
#include <linux/printk.h>

#include "config.h"
#include "../../include/const_def.h"
#include "../../include/path_def.h"
#include "../../dev_ctl_kernel/net_link_io.h"
 
#include "audit_list.h" 
#include "config.h" 
#include "data_type.h"
#include "policy_buffer.h"
#include "globals.h"
#include "ioctl.h"


#define DbgPrint printk
 
static void ioctlNetLink(struct sk_buff * skb);
static int processIoCtl(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid);
// --------------------------------------------------------------------------------------------
 
NETLINK_IO * g_kio = NULL;
 
int ioctl_module_init(void)
{
	g_kio = netlinkIoBuild(NETLINK_OS_SEC_MOD, ioctlNetLink);

	if(!g_kio){   
			printk(KERN_ALERT "[ioctlModuleInit] Error creating socket.\n");  
			return -10;  
	}  
	return 0;  	
} 

void ioctl_module_destroy(void)
{
	if(g_kio){
		xobject_release(g_kio);
		g_kio = NULL;
	}
	return;  	
} 

static void ioctlNetLink(struct sk_buff * skb)  
{
	int res;
	int pid;   
	int length = 0;
 	IOCTL_PACKET * inPkt = NULL;
	unsigned int portid = NETLINK_CB(skb).portid;
	res =  get_netlink_payload(skb, &pid, (char * *)&inPkt, &length);
	if(0 != res){
		printk("[ioctlNetLink] failed to call get_netlink_payload...\n");
		goto DONE;
	}
	
	if(length < sizeof(IOCTL_PACKET)){
		goto DONE;
	}
	
	if(length < (inPkt->hdr.cntLen + sizeof(IOCTL_PACKET))){
		goto DONE;
	}
 
	processIoCtl(g_kio, inPkt, portid);
DONE:	
	return;
}   

// -- res = send_net_link_data(get_sock(g_kio), pid, (unsigned char * ) msg, strlen(msg));
static int sendResponse(struct sock * sock, unsigned int portid, unsigned int code, void * cnt, unsigned int cntLen, unsigned int wParam, unsigned int lParam)
{
	int retval = -1;
	IOCTL_PACKET * pkt = NULL;
	unsigned int total = sizeof(IOCTL_PACKET) + cntLen;
	// -- long pid = current->pid;
	
	pkt = (IOCTL_PACKET *)kmalloc(total, GFP_KERNEL);
	if(!pkt) goto DONE;
	
	pkt->hdr.uCode = code;
	pkt->hdr.wParam = wParam;
	pkt->hdr.lParam = lParam;
	pkt->hdr.cntLen = cntLen;
	if(cntLen > 0){
		memcpy((void * )(pkt + 1), cnt, cntLen);
	}
	
	retval = send_net_link_data(sock, portid, (unsigned char * ) pkt, total);
DONE:	
	if(pkt){
		kfree(pkt);
	}
	return retval;
} 
  
/* 
int __IOCTLSetFlashRules(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_OK;
	PVOID ioBuffer;
	unsigned int inputBufferLength;
	unsigned int count;
	// -- long pid = current->pid;
	FLASH_RULE * rules;
	 
	ioBuffer = param->inputBuffer;
	inputBufferLength = param->hdr.cntLen;
	// -- outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
	// -- 
	count = inputBufferLength / sizeof(FLASH_RULE);
	if(0 != inputBufferLength % sizeof(FLASH_RULE)){
		ntStatus = __CTL_RESP_FAILED;
		goto DONE;
	}
 	rules = (FLASH_RULE *)ioBuffer;
	
	flashRuleTableSetRules(rules, count);
	// -- fwPortTableSetRules(&g_portTable, ranges, count);
 
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, NULL, 0, 0, 0); 
	return ntStatus;
}
 
*/
 
int __IOCTLSetConfig(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_OK;
	void * ioBuffer;
	unsigned int inputBufferLength;
	unsigned int __folder_len = 0;
	// -- unsigned int count;
	// -- long pid = current->pid;
	CONFIG_DATA * config;
	 
	ioBuffer = param->inputBuffer;
	inputBufferLength = param->hdr.cntLen;
	// -- outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
	// -- 
	// -- count = inputBufferLength / sizeof(CONFIG_DATA);
	if(inputBufferLength != sizeof(CONFIG_DATA)){
		ntStatus = __CTL_RESP_FAILED;
		goto DONE;
	}
	
	config = (CONFIG_DATA *)ioBuffer;
	printk("dir: %s", config->watchFolder);
	atomic_set(&g_globals.bWhiteListEnable, !!config->bWhiteListEnable);
	atomic_set(&g_globals.bWatchFileEvent, !!config->bWatchFileEvent);
	atomic_set(&g_globals.bAclEnable, !!config->bAclEnable);
	
	strncpy(g_globals.watchFolder, config->watchFolder, sizeof(g_globals.watchFolder));
	__folder_len = strlen(g_globals.watchFolder);
	if(__folder_len > 0){
		if(g_globals.watchFolder[__folder_len-1] != '/'){
			g_globals.watchFolder[__folder_len] = '/';
			g_globals.watchFolder[__folder_len+1] = 0;
		}
	}

	strncpy(g_globals.aclFolder, config->aclFolder, sizeof(g_globals.aclFolder));
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, NULL, 0, 0, 0); 
	return ntStatus;
}
 
int __IOCTLReadAudit(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_OK;
	int outCntLen = param->hdr.wParam;
	char * outBuffer = NULL;
	// -- long pid = current->pid;
	
	if(outCntLen <= 0){
		outCntLen = 0;
		ntStatus = __CTL_RESP_OK;
		goto DONE;
	}
	
	outBuffer = (char * )kmalloc(outCntLen, GFP_KERNEL);
	if(!outBuffer){
		ntStatus = __CTL_RESP_FAILED;
		goto DONE;
	}
	 
	ntStatus = read_audit(outBuffer, outCntLen, &outCntLen);
 
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, outBuffer, outCntLen, 0, 0); 
	if(outBuffer){
		kfree(outBuffer);
	}
	return ntStatus;
}
 

// --  
int __IOCTLLoadUserList(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_FAILED;
	unsigned int outCntLen = param->hdr.wParam;
 	int retval = -1;
	
	retval = read_userlist(SUBJECT_CFG_PATH);
	if(retval){
		printk("read userlist error %d\n",retval);
		goto DONE;
	}
	
	ntStatus = __CTL_RESP_OK;
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, (char * )NULL, 0, 0, 0); 
 
	return ntStatus;
}

int __IOCTLLoadFileList(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_FAILED;
	unsigned int outCntLen = param->hdr.wParam;
 	int retval = -1;
	
	retval = read_filelist(OBJECT_CFG_PATH);
	if(retval){
		printk("read filelist error %d\n",retval);
		goto DONE;
	}

	
	ntStatus = __CTL_RESP_OK;
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, (char * )NULL, 0, 0, 0); 
 
	return ntStatus;
}

// --  
int __IOCTLLoadPolicy(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int ntStatus = __CTL_RESP_FAILED;
	unsigned int outCntLen = param->hdr.wParam;
 	int retval = -1;
	
	retval = read_whitelist(HASHLIST_PATH, MAXLIST, DIGEST_SIZE);
	if(retval){
		printk("read whitelist error %d\n",retval);
		goto DONE;
	}

	
	ntStatus = __CTL_RESP_OK;
DONE:
 	ntStatus = sendResponse(get_sock(kio), portid, ntStatus, (char * )NULL, 0, 0, 0); 
 
	return ntStatus;
}
 
static int processIoCtl(NETLINK_IO * kio, IOCTL_PACKET * param, unsigned int portid)
{
	int bHandled = 0;
	int uCode = __CTL_RESP_OK;
	int retval = -1;
	// -- long pid = current->pid;
	
	switch(param->hdr.uCode){ 
	case XSECMODCTL_READ_AUDIT:
	 	retval = __IOCTLReadAudit(kio, param, portid);
		bHandled = 1;
		break;	
	case XSECMODCTL_SET_CONFIG:
		retval = __IOCTLSetConfig(kio, param, portid);
		bHandled = 1;
		break;
	case XSECMODCTL_LOAD_MAC_OBJECT_LIST:
		retval = __IOCTLLoadFileList(kio, param, portid);
		bHandled = 1;
		break;		
	case XSECMODCTL_LOAD_MAC_SUBJECT_LIST:
		retval = __IOCTLLoadUserList(kio, param, portid);
		bHandled = 1;
		break;		
	case XSECMODCTL_LOAD_WL_POLICY:
		retval = __IOCTLLoadPolicy(kio, param, portid);
		bHandled = 1;
		break;		
	default:
		DbgPrint("default ... \n");
		uCode = __CTL_RESP_FAILED; 
 		break;
	}	
	 
	// -- DONE:
	if(!bHandled){
		retval = sendResponse(get_sock(kio), portid, uCode, NULL, 0, 0, 0); 
	}	
	return retval;
}
  

